//
// Created by 罗俊华 on 2022/1/14.
//
#include <iostream>

using namespace std;

void char_pointer_and_char_array_and_string();

void copy_array();

void const_pointer_char();

void char_string_array();

int main() {

//    char_pointer_and_char_array_and_string();

//    copy_array();
//    const_pointer_char();
    char_string_array();
    return 0;
}

/**
 * char 指针、 char数组、 字符串常量 都被解释为 字符串中第一个字符的地址
 * */
void char_pointer_and_char_array_and_string() {

    char hello[] = "你太棒了";

//    将hello数组所指向字符串的第一个字符的地址赋值给指针，并不会复制字符串，而是复制地址。
    char *cp = hello;

    hello[0] = 'l';
    hello[1] = 'u';
    hello[2] = 'o';


    cout << "char[] 数组的内容是：" << hello << "，强转为地址是：" << (int *) hello << endl;

    cout << "cp* 指针的内容是：" << cp << "，强转为地址是：" << (int *) cp << endl;

    cout << "请输入一个字符" << endl;

    cin >> hello;

/*    拷贝字符串数组
 *      1、分配内存：新建一个数组用于存放字符串副本
 *      使用 new 创建数组可以动态分配数组长度
 *      strlen() +1 来动态获得 包含空字符 \0 时的长度
 */
    char *copy = new char[strlen(hello) + 1];

/*   2、拷贝内容
 *      应该确定分配了足够的空间，来存储存储副本；
 *      否则：strcpy() 将字符串中剩余部份复制到数组后面的内存字节中（⚠️危险）
 *      可以使用 strncpy() 来避免目标数组越界的问题
 */
    strcpy(copy, hello);

//    改变源数组，不会再影响副本的内容
    hello[0] = 'y';
    hello[1] = 'a';
    hello[2] = 'n';


    cout << "char[] 数组的内容是：" << hello << "，强转为地址是：" << (int *) hello << "，其字符串长度是：" << strlen(hello) << "，占用"
         << sizeof hello << "字节" << endl;

    cout << "copy* 指针的内容是：" << copy << "，强转为地址是：" << (int *) copy << "，其字符串长度是：" << strlen(cp) << "，占用" << sizeof cp
         << "字节" << endl;

//    释放内存
    delete[] copy;

}

/**
 * 拷贝数组
 * */
void copy_array() {


//     strcpy() 可能会将内容复制了超出 dest 目标数组的危险⚠️

    char resource[] = "hello,luo.";

    int dest_size = 6;
    char *dest = new char[dest_size];

//    注意：该函数在到达字符串结尾之前，dest的内存已经用完，则 dest 将不会添加空字符 '\0'
//          但如果 resource 的字符数量小于 dest_size -1 个字符，则复制完之后，会自动加上空字符 '\0'
//      第三个参数为：要复制的最大字节数
    strncpy(dest, resource, dest_size);

    cout << "刚复制完：" << dest << endl;

//    手动替换掉目标数组最后一个元素为空字符
    dest[dest_size - 1] = '\0';

    cout << "将目标数组的最后一个位置设置为空字符：" << dest << endl;

    char temp[] = "a";
    char *cc = temp;/*new char[2];
    cc[0] = 'a';
    cc[1] = '\0';*/
//    复制完成之后也不是自动加上'\0'，而是将 resource 源数组的 '\0' 拷贝到了 dest 之中而已
    strncpy(dest, cc, 1);

    cout << "n = " << 1 << '\t' << dest << endl;

    strncpy(dest, cc, 2);

    cout << "n = " << 2 << '\t' << dest << endl;

    strncpy(dest, cc, dest_size);

    cout << "n = dest" << ' ' << dest << endl;

//    delete[] cc;
}

/**
 * 常量字符串指向 常量char指针
 */
void const_pointer_char() {

//  在 c++  中，字符串被视为一个常量
//  所以第一个字符是常量指针
//  常量指针只能赋值给常量指针
//  const 不能省略
    const char *str_char = "你好，我是常量字符串";

    char arr[] = "我是数组";


    cout << str_char << endl
         << arr;
}

/**
 * char指针数组存储多个 常量字符串
 */
void char_string_array() {


//    arr 数组中存储的是 char指针 (char*)，每一个(char*)分别指向不同的字符串的第一个字符
    char const *arr[] = {
            "abc",
            "我是罗俊华",
            "拜拜"
    };

//        找到数组中的第 1 个元素
//        可见数组中的第 1 个元素存储的是 常量 char 指针 (const char *)
//          数组中的其他元素同理，只不过取 utf-8 编码比较麻烦
    const char *c_string = *arr;

//     遍历数组中的第一个元素中的 abc
    for (int i = 0; i < strlen(c_string); ++i) {

        cout << c_string << "中的第" << i << "个字符是：" << *(c_string + i) << endl;
    }

}